package com.jtw.sys.controller.user;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jtw.common.anno.RequestAnno.PermAnno;
import com.jtw.common.anno.findPagingAnno.FindPagingAnno;
import com.jtw.common.anno.findPagingAnno.FindPagingItemAnno;
import com.jtw.common.bean.Result.Message;
import com.jtw.common.bean.enums.ReqCode;
import com.jtw.common.bean.vo.FindPagingVo;
import com.jtw.common.bean.vo.FindParamVo;
import com.jtw.common.token.ClientToken;
import com.jtw.common.util.DeviceUtil;
import com.jtw.common.util.IpUtil;
import com.jtw.common.util.Validator;
import com.jtw.conf.shiro.CustomTypeToken;
import com.jtw.conf.shiro.enums.LoginType;
import com.jtw.sys.constants.Constant;
import com.jtw.sys.model.log.TSysUserLoginLog;
import com.jtw.sys.model.user.TSysUserInfo;
import com.jtw.sys.service.log.SysLoginServiceImpl;
import com.jtw.sys.service.perm.AuthService;
import com.jtw.sys.service.user.SysUserServiceImpl;
import com.jtw.sys.vo.user.SysUserAddReq;
import com.jtw.sys.vo.user.SysUserInfoBaseVo;
import com.jtw.sys.vo.user.SysUserInfoModifyReq;
import com.jtw.sys.vo.user.SysUserRolesModifyReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Api(tags = "系统用户管理模块")
@RestController
@Slf4j
@Validated //开启访问参数校验
@RequestMapping(value = "/sys/user")
public class SysUserController {
    @Autowired
    private SysUserServiceImpl sysUserServiceImpl;
    @Autowired
    private AuthService authService;
    @Autowired
    private SysLoginServiceImpl sysLoginService;
//    @Autowired
//    private RedisTemplate redisTemplate;

    @ApiOperation(notes = "公开权限组", value = "系统用户登录入口")
    @ApiImplicitParams({@ApiImplicitParam(name = "userName", value = "账号", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", paramType = "form"),
            @ApiImplicitParam(name = Constant.KEY_CAPTCHA, value = "验证码", required = true, dataType = "String", paramType = "form")})
    @Transactional
    @PostMapping(value = "/login")
    @PermAnno(sort = 1, group = 1, open = true)
    public Message login(@RequestParam @NotBlank(message = "用户名不能为空") String userName,
                         @RequestParam @NotBlank(message = "密码不能为空") String password,
                         @RequestParam @NotBlank(message = "验证码不能为空") String rand,
                         HttpSession httpsession,
                         HttpServletRequest request
    ) {
        Object rand1 = httpsession.getAttribute(Constant.KEY_CAPTCHA);
        if (rand1 == null) {
            return ReqCode.IndentifyCodeMissing.getMessage();
        }
        if (!rand.toUpperCase().equals(rand1.toString())) {
            return ReqCode.IndentifyCodeError.getMessage();
        }
        CustomTypeToken usernamePasswordToken = new CustomTypeToken(userName, password,LoginType.PASSWORD,false,"");
        Subject subject = SecurityUtils.getSubject();

        //检测用户登陆信息
        try {
            usernamePasswordToken.setRememberMe(true);
            subject.login(usernamePasswordToken);
        } catch (IncorrectCredentialsException ice) {
            // 密码错误异常
            throw ReqCode.SysLoginPasswordError.getException();
        } catch (UnknownAccountException uae) {
            // 未知用户名异常
            throw ReqCode.SysLoginUnKnowAccount.getException();
        } catch (ExcessiveAttemptsException eae) {
            // 错误登录过多的异常
            throw ReqCode.SysLoginExcessiveAttempts.getException();
        } catch (LockedAccountException lae) {
            //账号锁定异常
            throw ReqCode.SysLoginLockedAccount.getException();
        }

//        开启redis session管理的化 需要激活次方法 限制同一账号多端登陆
//        Object sessionid = redisTemplate.opsForValue().get(userName);
//        if(sessionid!=null){
//            //如果有 则前面的session失效；
//            redisTemplate.delete(Constant.KEY_SPRING_SESSION_PREFFIX+sessionid.toString());
//            redisTemplate.expire(Constant.KEY_SPRING_SESSION_EXPIRES_PREFFIX+sessionid.toString(),0,TimeUnit.SECONDS);
//        }
//        redisTemplate.opsForValue().set(userName,subject.getSession().getId(),3600,TimeUnit.SECONDS);





        //登录成功之后删除rand
        httpsession.removeAttribute(Constant.KEY_CAPTCHA);
        SysUserInfoBaseVo sysUserInfoBaseVo = sysUserServiceImpl.getUserInfoBaseVoByUserName(userName);

        if(!sysUserServiceImpl.isAdmin(sysUserInfoBaseVo.getId())){
            return ReqCode.isNotAdmin.getMessage();
        }
        //创建客户端的用户信息token
        ClientToken clientToken = new ClientToken();
        //更新登陆时间
        sysUserServiceImpl.updateUserLoginTime(sysUserInfoBaseVo.getId());
//        clientToken.setInfo(sysUserInfoBaseVo); //此处不需要获取用户信息了

        //生成跨域token
        String csrfToken = UUID.randomUUID().toString().replace("-", "");
        subject.getSession().setAttribute(Constant.KEY_USER_INFO, sysUserInfoBaseVo); //存储基本信息
        subject.getSession().setAttribute(Constant.KEY_USER_USER_NAME, userName); //存储基本信息
        subject.getSession().setAttribute(Constant.USER_PRIMARY_KEY, sysUserInfoBaseVo.getId());
        subject.getSession().setAttribute(Constant.KEY_CSRF_TOKEN, csrfToken);
        //插入登陆记录
        sysLoginService.saveLoinLog(request,sysUserInfoBaseVo.getId(),1);

        //生成登陆成功的返回信息
        Map<String, String> map = new HashMap<String, String>();
        map.put(Constant.KEY_CLIENT_TOKEN, ClientToken.createClientToken(clientToken));
        map.put(Constant.KEY_CSRF_TOKEN, csrfToken);
        return ReqCode.Success.getMessage(map);
    }

    @ApiOperation(notes = "公开权限组", value = "未登录提示接口")
    @GetMapping("/unLogin")
    @PermAnno(sort = 2, group = 1, open = true)
    public Message unLogin() {
        return ReqCode.UnLogin.getMessage();
    }

    @ApiOperation(notes = "公开权限组", value = "无权限操作提示")
    @GetMapping("/noPermission")
    @PermAnno(sort = 3, group = 1, open = true)
    public Message noPermission() {
        return ReqCode.NoPermission.getMessage();
    }

    @ApiOperation(notes = "系统用户管理", value = "查询所有系统用户")
    @FindPagingAnno(
            items = {
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "userName"),
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "mobile"),
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "nickName"),
                    @FindPagingItemAnno(conditions = {"LIKE"}, column = "address"),
                    @FindPagingItemAnno(column = "sex", fixedValue = {"1", "2", "0"}, isString = false),
                    @FindPagingItemAnno(column = "state", fixedValue = {"0", "1"}, isString = false,prefix = "`t_sys_user`."),
                    @FindPagingItemAnno(column = "age", conditions = {">", "<", ">=", "<=", "="}, isString = false),
                    @FindPagingItemAnno(conditions = {">", "<", ">=", "<=", "="}, column = "createTime", prefix = "`t_sys_user_info`."),
            })
    @GetMapping("/findAllUserInfoBaseVo")
    @PermAnno(sort = 1, group = 5)
    public Message findAllUserInfoBaseVo(@Valid FindPagingVo findPagingVo) {
        return ReqCode.Success.getMessage(sysUserServiceImpl.findAllUserInfoBaseVo(findPagingVo));
    }

    @ApiOperation(notes = "系统用户管理", value = "查询所有后台管理员用户")
    @FindPagingAnno(
            items = {
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "userName"),
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "mobile"),
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "nickName"),
                    @FindPagingItemAnno(conditions = {"LIKE"}, column = "address"),
                    @FindPagingItemAnno(column = "sex", fixedValue = {"1", "2", "0"}, isString = false),
                    @FindPagingItemAnno(column = "state", fixedValue = {"0", "1"}, isString = false,prefix = "`t_sys_user`."),
                    @FindPagingItemAnno(column = "age", conditions = {">", "<", ">=", "<=", "="}, isString = false),
                    @FindPagingItemAnno(conditions = {">", "<", ">=", "<=", "="}, column = "createTime", prefix = "`t_sys_user_info`."),
            })
    @GetMapping("/findAllAdminUserInfoBaseVo")
    @PermAnno(sort = 12, group = 5)
    public Message findAllAdminUserInfoBaseVo(@Valid FindPagingVo findPagingVo) {
        return ReqCode.Success.getMessage(sysUserServiceImpl.findAllAdminUserInfoBaseVo(findPagingVo));
    }

    @ApiOperation(notes = "系统用户管理", value = "添加管理账号")
    @PostMapping("/addSysUserAccount")
    @PermAnno(sort = 2, group = 5)
    public Message addSysUserAccount(@Valid SysUserAddReq sysUserAddReq,HttpServletRequest request) {
        if(!Validator.isEnAndNumber(sysUserAddReq.getUserName())){
            return ReqCode.isNotTrueAccountFormat.getMessage();
        }
        sysUserServiceImpl.addSysUserAccount(sysUserAddReq,request);
        return ReqCode.AddSuccess.getMessage();
    }

    @ApiOperation(notes = "系统用户管理", value = "锁定用户账号")
    @PostMapping("/lockSysUserAccount")
    @PermAnno(sort = 3, group = 5)
    public Message lockSysUserAccount(@NotNull(message = "用户id不能为空") Long id) {
        sysUserServiceImpl.lockedSysUserAccount(id);
        return ReqCode.UpdateSuccess.getMessage();
    }

    @ApiOperation(notes = "系统用户管理", value = "解锁用户账号")
    @PostMapping("/unlockSysUserAccount")
    @PermAnno(sort = 4, group = 5)
    public Message unlockSysUserAccount(@NotNull(message = "用户id不能为空") Long id) {
        sysUserServiceImpl.unlockedSysUserAccount(id);
        return ReqCode.UpdateSuccess.getMessage();
    }

    @GetMapping("/getUserRolesByUserId")
    @PermAnno(sort = 7, group = 5)
    @ApiOperation(notes = "系统用户角色管理", value = "获取单个用户的角色")
    public Message getUserRolesByUserId(@NotNull(message = "用户id不能为空") Long userId) {
        return ReqCode.UpdateSuccess.getMessage(sysUserServiceImpl.getUserRolesByUserId(userId));
    }

    @ApiOperation(notes = "系统用户角色管理", value = "修改单个用户角色")
    @PostMapping("/modifyUserRolesByUserId")
    @PermAnno(sort = 5, group = 5)
    public Message modifyUserRolesByUserId(@Valid SysUserRolesModifyReq sysUserRolesModifyReq,HttpServletRequest request) {
        sysUserServiceImpl.modifyUserRolesByUserId(sysUserRolesModifyReq.getUserId(), sysUserRolesModifyReq.getRoleList(),request);
        return ReqCode.UpdateSuccess.getMessage();
    }

    @ApiOperation(notes = "系统用户基本信息管理", value = "修改单个用户基本信息")
    @PostMapping("/modifySysUserBaseInfoByUserId")
    @PermAnno(sort = 6, group = 5)
    public Message modifySysUserBaseInfoByUserId(HttpServletRequest request,@Valid SysUserInfoModifyReq sysUserInfoModifyReq) {
        TSysUserInfo sysUserInfo = new TSysUserInfo();
        BeanUtils.copyProperties(sysUserInfoModifyReq, sysUserInfo);
        sysUserInfo.setOperator((String) request.getSession().getAttribute(Constant.KEY_USER_USER_NAME));
        sysUserInfo.setOperatorIp(request.getRemoteAddr());
        sysUserServiceImpl.modifySysUserBaseInfoByUserId(sysUserInfo);
        return ReqCode.UpdateSuccess.getMessage();
    }

    @ApiOperation(notes = "系统用户权限管理", value = "获取单个用户所有权限")
    @GetMapping("/getAllPermsBySysUserId")
    @PermAnno(sort = 7, group = 5)
    public Message getAllPermsBySysUserId(@NotNull(message = "用户id不能为空")  Long userId) {
        return ReqCode.SelectSuccess.getMessage(sysUserServiceImpl.getAllPermsBySysUserId(userId));
    }
    @ApiOperation(notes = "系统用户权限管理", value = "是否用户登陆后台")
    @PostMapping("/lockSysUserAdminLoginPerm")
    @PermAnno(sort = 10, group = 5)
    public Message modifySysUserAdminLoginPerm(@NotNull(message = "用户id不能为空")  Long id) {
        sysUserServiceImpl.modifySysUserAdminLoginPerm(id);
        return ReqCode.UpdateSuccess.getMessage();
    }

    @ApiOperation(notes = "系统用户权限管理", value = "获取单个用户【未拥有】的角色")
    @GetMapping("/getRolesByUserIdNotHave")
    @PermAnno(sort = 8, group = 5)
    public Message getRolesByUserIdNotHave(@NotNull(message = "用户id不能为空") Long userId) {
        return ReqCode.UpdateSuccess.getMessage(sysUserServiceImpl.getAllRolesByUserIdNotHave(userId));
    }

    @ApiOperation(notes = "系统用户基本信息管理", value = "修改单个用户的密码")
    @PostMapping("/modifyAccountPwdByUserId")
    @PermAnno(sort = 9, group = 5)
    public Message modifyAccountPwdByUserId(@NotNull(message = "用户id不能为空") Long userId, @NotBlank(message = "新密码不能为空") String newPassword) {
        sysUserServiceImpl.modifyAccountPwdByUserId(userId, newPassword);
        return ReqCode.UpdateSuccess.getMessage();
    }

    @ApiOperation(notes = "系统登陆可用组", value = "获取当前管理员的基本信息")
    @GetMapping("/getSysUserBaseInfoVo")
    @PermAnno(sort = 3, group = 99)
    public Message getSysUserBaseInfoVo() {
        Long userId = (Long) SecurityUtils.getSubject().getSession().getAttribute(Constant.USER_PRIMARY_KEY);
        SysUserInfoBaseVo sysUserInfoBaseVo = sysUserServiceImpl.getUserInfoBaseVoByUserId(userId);

        SecurityUtils.getSubject().getSession().setAttribute(Constant.KEY_USER_INFO, sysUserInfoBaseVo);
        ObjectMapper objectMapper = new ObjectMapper();
        String user=null;
        try {
             user = Base64.getEncoder().encodeToString(objectMapper.writeValueAsString(sysUserInfoBaseVo).getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return ReqCode.SelectSuccess.getMessage(user);
    }

    @ApiOperation(notes = "系统登陆可用组", value = "系统用户退出登录")
    @PostMapping("/logout")
    @PermAnno(sort = 1, group = 99)
    public Message logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        subject.getSession().removeAttribute(Constant.KEY_USER_INFO);
        return ReqCode.Success.getMessage();
    }

    @ApiOperation(notes = "系统用户基本信息管理", value = "查询所有登陆密码重置申请")
    @FindPagingAnno(
            items = {
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "userName"),
                    @FindPagingItemAnno(conditions = {"=", "LIKE"}, column = "reason"),
                    @FindPagingItemAnno(column = "state", fixedValue = {"0", "1","2"}, isString = false),
                    @FindPagingItemAnno(conditions = {">", "<", ">=", "<=", "="}, column = "createTime", prefix = "`t_sys_member_pwd_reset`."),
            })
    @GetMapping("/findAllPwdResetApply")
    @PermAnno(sort = 12, group = 5)
    public Message findAllPwdResetApply(@Valid FindPagingVo findPagingVo) {
        return ReqCode.Success.getMessage(sysUserServiceImpl.findAllPwdResetApply(findPagingVo));
    }


    @ApiOperation(notes = "系统用户基本信息管理", value = "确认登陆密码重置申请")
    @PostMapping("/confirmPwdResetApply")
    @PermAnno(sort = 14, group = 5)
    public Message confirmPwdResetApply(HttpServletRequest request,@NotNull(message = "id不能为空") Long id) {
        sysUserServiceImpl.confirmPwdResetApply(request,id);
        return ReqCode.SubmitSuccess.getMessage();
    }
    @ApiOperation(notes = "系统用户基本信息管理", value = "拒绝登陆密码重置申请")
    @PostMapping("/refusedPwdResetApply")
    @PermAnno(sort = 14, group = 5)
    public Message refusedPwdResetApply(HttpServletRequest request,@NotNull(message = "id不能为空") Long id,@NotBlank(message = "拒绝理由不能为空")String reason) {
        sysUserServiceImpl.refusedPwdResetApply(request,id,reason);
        return ReqCode.SubmitSuccess.getMessage();
    }

    @ApiOperation(notes = "会员登陆可用组", value = "查询所有签到记录")
    @GetMapping("/findAllCheckInReward")
    @PermAnno(sort = 16, group = 5)
    @FindPagingAnno(
            items = {
                    @FindPagingItemAnno(conditions = {">", "<", ">=", "<=", "="}, column = "createTime", prefix = "`t_sys_member_check_in`."),
                    @FindPagingItemAnno(conditions = {"=","LIKE"}, column = "userName", prefix = "`t_sys_member_check_in`.")
            })
    public Message findAllCheckInReward(@Valid FindPagingVo findPagingVo) {
        return ReqCode.SelectSuccess.getMessage(sysUserServiceImpl.findAllCheckInReward(findPagingVo));
    }
}
